package com.zmn.mcc.business.impl.staff.log;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.mcc.business.interfaces.staff.ip.StaffIpInfoBService;
import com.zmn.mcc.business.interfaces.staff.log.StaffLogBService;
import com.zmn.mcc.model.entity.staff.log.IpInfoVo;
import com.zmn.mcc.model.entity.staff.log.StaffLogQuery;
import com.zmn.mcc.model.entity.staff.log.StaffLogVO;
import com.zmn.mcc.model.entity.staff.log.StaffReqVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class StaffLogBServiceImpl implements StaffLogBService {

    @Resource
    MongoTemplate mongoTemplate;

    @Resource
    StaffIpInfoBService staffIpInfoBService;
    /**
     * 描述: 员工操作日志mongo 标识
     */
    public final static String STAFF_OPERATE_LOG = "staff_operate_log";

    @Override
    public List<StaffLogVO> listPageByQuery(StaffLogQuery query) {
        Query queryMongo = new Query();

        if (Objects.nonNull(query.getStaffId())) {
            queryMongo.addCriteria(Criteria.where("staffId").is(query.getStaffId()));
        }
        if (StringUtils.isNotEmpty(query.getRealName())) {
            Pattern realName = Pattern.compile("^.*" + query.getRealName() + ".*$", Pattern.CASE_INSENSITIVE);
            queryMongo.addCriteria(Criteria.where("realName").is(realName));
        }
        if (NumberUtil.isPositiveInteger(query.getCompanyId())) {
            queryMongo.addCriteria(Criteria.where("companyId").is(query.getCompanyId()));
        }
        if (NumberUtil.isPositiveInteger(query.getPlat())) {
            queryMongo.addCriteria(Criteria.where("plat").is(query.getPlat()));
        }
        if (NumberUtil.isPositiveInteger(query.getDeptId())) {
            queryMongo.addCriteria(Criteria.where("deptId").is(query.getDeptId()));
        }
        if (StringUtils.isNotEmpty(query.getDeptName())) {
            Pattern deptName = Pattern.compile("^.*" + query.getDeptName() + ".*$", Pattern.CASE_INSENSITIVE);
            queryMongo.addCriteria(Criteria.where("deptName").is(deptName));
        }
        if (StringUtils.isNotEmpty(query.getUri())) {
            queryMongo.addCriteria(Criteria.where("uri").is(query.getUri()));
        }
        if (StringUtils.isNotEmpty(query.getApp())) {
            queryMongo.addCriteria(Criteria.where("app").is(query.getApp()));
        }
        if (StringUtils.isNotEmpty(query.getIp())) {
            queryMongo.addCriteria(Criteria.where("ip").is(query.getIp()));
        }
        if (Objects.nonNull(query.getStartTime()) && Objects.nonNull(query.getEndTime())) {
            queryMongo.addCriteria(Criteria.where("time").gte(query.getStartTime()).lte(query.getEndTime()));
        }
        if (Objects.nonNull(query.getStartTime()) && Objects.isNull(query.getEndTime())) {
            queryMongo.addCriteria(Criteria.where("time").gte(query.getStartTime()));
        }
        if (Objects.isNull(query.getStartTime()) && Objects.nonNull(query.getEndTime())) {
            queryMongo.addCriteria(Criteria.where("time").lte(query.getEndTime()));
        }

        int pageNum = NumberUtil.isNullOrZero(query.getPageNum()) ? 0 : query.getPageNum() - 1;
        int pageSize = NumberUtil.isNullOrZero(query.getPageSize()) ? 50 : query.getPageSize();
        queryMongo.skip(pageNum * pageSize).limit(pageSize);

        long count = mongoTemplate.count(queryMongo, StaffLogVO.class, STAFF_OPERATE_LOG);

        if (count % pageSize == 0) {
            query.setTotalCount(pageNum * pageSize + pageSize + 1);
        } else {
            query.setTotalCount(pageNum * pageSize + (int) count);
        }


        queryMongo.with(Sort.by(Sort.Direction.DESC, "time"));
        List<StaffLogVO> staffLogVOList = mongoTemplate.find(queryMongo, StaffLogVO.class, STAFF_OPERATE_LOG);
        //解析req
        resolveReq(staffLogVOList);
        //获取ip信息
        getIpInfo(staffLogVOList);
        return staffLogVOList;
    }

    @Override
    public StaffLogVO findById(String id) {
        StaffLogVO staffLogVO = mongoTemplate.findById(id, StaffLogVO.class, STAFF_OPERATE_LOG);
        if (null == staffLogVO) {
            return new StaffLogVO();
        }
        //解析ip
        getIpInfo(staffLogVO);
        return staffLogVO;
    }

    /**
     * 解析req数据
     * @param staffLog
     */
    @Override
    public StaffReqVo resolveReq(StaffLogVO staffLog) {
        if (StringUtils.isEmpty(staffLog.getReq()) && StringUtils.isEmpty(staffLog.getRes())) {
            return new StaffReqVo();
        }
        StaffReqVo staffReqVo = new StaffReqVo();
        if (StringUtils.isNotEmpty(staffLog.getReq())) {
            JSONObject req = JSON.parseObject(staffLog.getReq());
            staffReqVo.setCookie(req.getString("Cookie"));
            staffReqVo.setSession(req.getString("session"));
            staffReqVo.setUserAgent(req.getString("User-Agent"));
            staffReqVo.setMethod(req.getString("method"));
            staffReqVo.setReferer(req.getString("Referer"));
            staffReqVo.setParams(req.getString("params"));
        }
        if (StringUtils.isNotEmpty(staffLog.getRes())) {
            JSONObject res = JSON.parseObject(staffLog.getRes());
            staffReqVo.setContentLenth(res.getString("Content-Length"));
            staffReqVo.setStatus(res.getInteger("status"));
            staffReqVo.setContentType(res.getString("Content-Type"));
        }
        return staffReqVo;
    }

    /**
     * 解析req获取 method session userAgent等信息
     * @param staffLogVOList
     */
    private void resolveReq(List<StaffLogVO> staffLogVOList) {
        if (CollectionUtil.isNullOrEmpty(staffLogVOList)) {
            return;
        }
        for (StaffLogVO staffLog : staffLogVOList) {
            if (StringUtils.isEmpty(staffLog.getReq())) {
                continue;
            }
            JSONObject reqJson = JSON.parseObject(staffLog.getReq());
            staffLog.setMethod(reqJson.getString("method"));
        }
    }

    /**
     * 获取ip详细信息
     */
    private void getIpInfo(List<StaffLogVO> staffLogVOList) {
        List<String> ipList = staffLogVOList.stream().map(StaffLogVO::getIp).collect(Collectors.toList());
        if (CollectionUtil.isNullOrEmpty(ipList)) {
            return;
        }
        //过滤掉内网ip和本地ip
        ipList = ipList.stream()
                .filter(e -> !StaffIpInfoBService.LOCAL_IP.equals(e) && !e.contains(StaffIpInfoBService.INTRANET))
                .collect(Collectors.toList());
        if (CollectionUtil.isNullOrEmpty(ipList)) {
            return;
        }

        List<IpInfoVo> ipInfoVoList = staffIpInfoBService.listIpInfo(ipList);
        Map<String, IpInfoVo> ipInfoVoMap = ipInfoVoList.stream()
                .collect(Collectors.toMap(IpInfoVo::getIp, e -> e, (e1, e2) -> e2));
        for (StaffLogVO staffLogVO : staffLogVOList) {
            IpInfoVo ipInfoVo = ipInfoVoMap.containsKey(staffLogVO.getIp()) ?
                    ipInfoVoMap.get(staffLogVO.getIp()) : new IpInfoVo();
            staffLogVO.setIpInfoVo(ipInfoVo);
        }
    }

    /**
     * 获取ip详细信息
     */
    private void getIpInfo(StaffLogVO staffLog) {
        if (StringUtils.isEmpty(staffLog.getIp())) {
            return;
        }
        List<String> ipList = Arrays.asList(staffLog.getIp());
        List<IpInfoVo> ipInfoVoList = staffIpInfoBService.listIpInfo(ipList);
        if (CollectionUtil.isNullOrEmpty(ipInfoVoList)) {
            return;
        }
        staffLog.setIpInfoVo(ipInfoVoList.get(0));
    }
}
